home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Format 1995 June
/
MacFormat 25.iso
/
Shareware City
/
Developers
/
OutOfPhase1.1 Source
/
OutOfPhase Folder
/
ASTLoop.c
< prev
next >
Wrap
Text File
|
1994-08-15
|
8KB
|
270 lines
/* ASTLoop.c */
/*****************************************************************************/
/* */
/* Out Of Phase: Digital Music Synthesis on General Purpose Computers */
/* Copyright (C) 1994 Thomas R. Lawrence */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* */
/* Thomas R. Lawrence can be reached at tomlaw@world.std.com. */
/* */
/*****************************************************************************/
#include "MiscInfo.h"
#include "Audit.h"
#include "Debug.h"
#include "Definitions.h"
#include "ASTLoop.h"
#include "ASTExpression.h"
#include "TrashTracker.h"
#include "Memory.h"
struct ASTLoopRec
{
LoopTypes KindOfLoop;
ASTExpressionRec* ControlExpression;
ASTExpressionRec* BodyExpression;
long LineNumber;
};
/* create a new loop node */
ASTLoopRec* NewLoop(LoopTypes LoopType, struct ASTExpressionRec* ControlExpr,
struct ASTExpressionRec* BodyExpr,
struct TrashTrackRec* TrashTracker, long LineNumber)
{
ASTLoopRec* Loop;
CheckPtrExistence(ControlExpr);
CheckPtrExistence(BodyExpr);
CheckPtrExistence(TrashTracker);
Loop = (ASTLoopRec*)AllocTrackedBlock(sizeof(ASTLoopRec),TrashTracker);
if (Loop == NIL)
{
return NIL;
}
SetTag(Loop,"ASTLoopRec");
Loop->LineNumber = LineNumber;
Loop->KindOfLoop = LoopType;
Loop->ControlExpression = ControlExpr;
Loop->BodyExpression = BodyExpr;
return Loop;
}
/* type check the loop node. this returns eCompileNoError if */
/* everything is ok, and the appropriate type in *ResultingDataType. */
CompileErrors TypeCheckLoop(DataTypes* ResultingDataType,
ASTLoopRec* Loop, long* ErrorLineNumber,
struct TrashTrackRec* TrashTracker)
{
CompileErrors Error;
DataTypes ConditionalType;
DataTypes BodyType;
CheckPtrExistence(Loop);
CheckPtrExistence(TrashTracker);
Error = TypeCheckExpression(&ConditionalType,Loop->ControlExpression,
ErrorLineNumber,TrashTracker);
if (Error != eCompileNoError)
{
return Error;
}
if (ConditionalType != eBoolean)
{
*ErrorLineNumber = Loop->LineNumber;
return eCompileConditionalMustBeBoolean;
}
Error = TypeCheckExpression(&BodyType,Loop->BodyExpression,ErrorLineNumber,
TrashTracker);
if (Error != eCompileNoError)
{
return Error;
}
*ResultingDataType = BodyType;
return eCompileNoError;
}
/* generate code for a loop. returns True if successful, or False if it fails. */
MyBoolean CodeGenLoop(struct PcodeRec* FuncCode,
long* StackDepthParam, ASTLoopRec* Loop)
{
long StackDepth;
long WhileBranchPatchupLocation EXECUTE(= -1);
long LoopBackAgainLocation;
CheckPtrExistence(FuncCode);
CheckPtrExistence(Loop);
StackDepth = *StackDepthParam;
/* this is the loopie thing. the only real difference between a while and */
/* a repeat loop is that the while has an extra branch to the test. */
/* repeat loop: */
/* - push default return value */
/* - pop previous value */
/* - evaluate body */
/* - perform test */
/* - branch if we keep looping to the pop previous value point */
/* while loop: */
/* - push default return value */
/* - jump to the test */
/* - pop previous value */
/* - evaluate body */
/* - perform test */
/* - branch if we keep looping to the pop previous value point */
/* push the default value -- same type as the body expression has */
switch (GetExpressionsResultantType(Loop->BodyExpression))
{
default:
EXECUTE(PRERR(ForceAbort,"CodeGenLoop: bad type of body expression"));
break;
case eBoolean:
case eInteger:
case eFixed:
if (!AddPcodeInstruction(FuncCode,epLoadImmediateInteger,NIL))
{
return False;
}
if (!AddPcodeOperandInteger(FuncCode,0))
{
return False;
}
break;
case eFloat:
if (!AddPcodeInstruction(FuncCode,epLoadImmediateFloat,NIL))
{
return False;
}
if (!AddPcodeOperandFloat(FuncCode,0))
{
return False;
}
break;
case eDouble:
if (!AddPcodeInstruction(FuncCode,epLoadImmediateDouble,NIL))
{
return False;
}
if (!AddPcodeOperandDouble(FuncCode,0))
{
return False;
}
break;
case eArrayOfBoolean:
case eArrayOfInteger:
case eArrayOfFloat:
case eArrayOfDouble:
case eArrayOfFixed:
if (!AddPcodeInstruction(FuncCode,epLoadImmediateNILArray,NIL))
{
return False;
}
break;
}
StackDepth += 1;
ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
"CodeGenLoop: stack depth error after pushing default value"));
/* if loop is a head-tested loop (while loop) then insert extra branch */
if ((Loop->KindOfLoop == eLoopWhileDo) || (Loop->KindOfLoop == eLoopUntilDo))
{
if (!AddPcodeInstruction(FuncCode,epBranchUnconditional,
&WhileBranchPatchupLocation))
{
return False;
}
if (!AddPcodeOperandInteger(FuncCode,-1/*target unknown*/))
{
return False;
}
}
/* remember this address! */
LoopBackAgainLocation = PcodeGetNextAddress(FuncCode);
/* pop previous result */
if (!AddPcodeInstruction(FuncCode,epStackPop,NIL))
{
return False;
}
StackDepth -= 1;
ERROR(StackDepth != *StackDepthParam,PRERR(ForceAbort,
"CodeGenLoop: stack depth error after popping previous"));
/* evaluate the body */
if (!CodeGenExpression(FuncCode,&StackDepth,Loop->BodyExpression))
{
return False;
}
ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
"CodeGenLoop: stack depth error after evaluating body"));
/* patch up the while branch */
if ((Loop->KindOfLoop == eLoopWhileDo) || (Loop->KindOfLoop == eLoopUntilDo))
{
ResolvePcodeBranch(FuncCode,WhileBranchPatchupLocation,
PcodeGetNextAddress(FuncCode));
}
/* evaluate the test */
if (!CodeGenExpression(FuncCode,&StackDepth,Loop->ControlExpression))
{
return False;
}
ERROR(StackDepth != *StackDepthParam + 2,PRERR(ForceAbort,
"CodeGenLoop: stack depth error after evaluating control"));
/* do the appropriate branch */
if ((Loop->KindOfLoop == eLoopWhileDo) || (Loop->KindOfLoop == eLoopDoWhile))
{
/* "while do" and "do while" need a branch if true conditional */
if (!AddPcodeInstruction(FuncCode,epBranchIfNotZero,NIL))
{
return False;
}
if (!AddPcodeOperandInteger(FuncCode,LoopBackAgainLocation))
{
return False;
}
}
else
{
/* "until do" and "do until" need a branch if false conditional */
if (!AddPcodeInstruction(FuncCode,epBranchIfZero,NIL))
{
return False;
}
if (!AddPcodeOperandInteger(FuncCode,LoopBackAgainLocation))
{
return False;
}
}
StackDepth -= 1;
ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
"CodeGenLoop: stack depth error after control branch"));
*StackDepthParam = StackDepth;
return True;
}